package com.gitee.cashzhang27.test.boot.crypt.mapper.component;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.TypeReference;
import com.gitee.cashzhang27.test.boot.crypt.mapper.annotation.Desensitize;
import com.gitee.cashzhang27.test.boot.crypt.mapper.annotation.DesensitizeFiled;
import com.gitee.cashzhang27.test.boot.crypt.mapper.entity.ObjectRestResponse;
import com.gitee.cashzhang27.test.boot.crypt.mapper.entity.TableResultResponse;
import com.gitee.cashzhang27.test.boot.crypt.mapper.util.DesensitizeUtils;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.lang.NonNull;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

/**
 * @author Cash Zhang
 * @version v1.0
 * @since 2019/07/11 15:14
 */
@Slf4j
@ControllerAdvice
public class DesensitizeResponseBodyAdvice implements ResponseBodyAdvice {

  @Override
  public boolean supports(@NonNull MethodParameter returnType, @NonNull Class converterType) {
    return true;
  }

  @Override
  public Object beforeBodyWrite(Object body, @NonNull MethodParameter returnType,
      @NonNull MediaType selectedContentType, @NonNull Class selectedConverterType,
      @NonNull ServerHttpRequest request,
      @NonNull ServerHttpResponse response) {
    Desensitize desensitize = returnType.getMethodAnnotation(Desensitize.class);
    if (Objects.nonNull(desensitize)) {
      Class clazz = desensitize.clazz();
      Field[] declaredFields = clazz.getDeclaredFields();
      Map<String, String> map = new HashMap<>();
      for (Field field : declaredFields) {
        if (field.getAnnotation(DesensitizeFiled.class) != null) {
          DesensitizeFiled desensitizeFiled = field
              .getAnnotation(DesensitizeFiled.class);
          map.put(field.getName(), desensitizeFiled.type().name());
        }
      }
      if (body instanceof ObjectRestResponse) {
        ObjectRestResponse restResponse = (ObjectRestResponse) body;
        Object data = restResponse.getData();
        return DesensitizeUtils.desensitizeObject(data, map);
      } else if (body instanceof TableResultResponse) {
        TableResultResponse resultResponse = (TableResultResponse) body;
        List<Object> paramList = Convert.convert(new TypeReference<List<Object>>() {
        }, resultResponse.getData().getRows());
        return DesensitizeUtils.desensitizeList(paramList, map);
      }
      if (body instanceof ArrayList) {
        List<Object> paramList = Convert.convert(new TypeReference<List<Object>>() {
        }, body);
        return DesensitizeUtils.desensitizeList(paramList, map);
      } else {
        return DesensitizeUtils.desensitizeObject(body, map);
      }
    }
    return body;
  }

}
